package scanner

import (
    "bufio"
    "errors"
    "fmt"
    "os"
    "reflect"
    "strconv"
    "strings"
)

// 读取配置文件
func ReadFile(path string) (config map[string]map[string]interface{}, err error) {
    config = make(map[string]map[string]interface{})
    f, err := os.OpenFile(path, os.O_RDONLY, os.ModePerm)
    if err != nil {
        return
    }
    defer f.Close()

    scanner := bufio.NewScanner(f)
    section := ""
    begin := false
    for scanner.Scan() {
        line := strings.TrimSpace(scanner.Text())
        // 空行
        if len(line) == 0 {
            continue
        }
        // 注释
        if line[0] == '#' {
            continue
        }

        // 开始分析
        if line[len(line)-1] == '{' {
            // 开始
            section = strings.Split(line, " ")[0]
            config[section] = make(map[string]interface{})
            begin = true
        } else if line[0] == '}' {
            // 结束
            begin = false
            section = ""
        } else if begin {
            // 分析配置项
            k, v, err := analyse(line)
            if err != nil {
                return config, err
            }

            config[section][k] = v
        }
    }

    return
}

// 根据配置文件说明的类型返回转换后的值
func SwitchStringType(t, v string) (res interface{}, err error) {
    switch t {
    case "B":
        res, err = strconv.ParseBool(v)
    case "S":
        res = v
    case "I":
        res, err = strconv.ParseInt(v, 10, 64)
    case "D":
        res, err = strconv.ParseFloat(v, 64)
    default:
        err = errors.New(fmt.Sprint("Unknown type", t))
    }
    return
}

// 根据变量实际类型返回配置文件说明的类型
func SwitchReflectType(v interface{}) (t string, err error) {
    rv := reflect.ValueOf(v)
    switch rv.Kind() {
    case reflect.Bool:
        t = "B"
    case reflect.String:
        t = "S"
    case reflect.Int64:
        t = "I"
    case reflect.Float64:
        t = "D"
    default:
        err = errors.New(fmt.Sprint("Unknown type", rv.Kind()))
    }
    return
}

func split(s, seq string, vars ...*string) {
    for i, v := range strings.SplitN(s, seq, 2) {
        if i > 1 {
            fmt.Println(s)
            break
        }
        *vars[i] = v
    }
}

// 分析配置项
func analyse(line string) (k string, rv interface{}, err error) {
    var t, v string
    split(line, ":", &t, &k)
    split(k, "=", &k, &v)

    rv, err = SwitchStringType(t, v)

    return
}
